package com.xgp.company.创建型模式.第一种_单例模式.DCL_懒汉式;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 *  双重检测—懒汉式
 * 核心：保证一个类只有一个实例，并且提供一个范围该实例的全局访问点
 */
public class SingletonDemo03 {

    //破坏两次都用反射创建对象
    private static boolean flag = false;

    //保证类只有一个实例，私有其构造器
    private SingletonDemo03() {
        //防治被反射
        synchronized (SingletonDemo03.class) {
            if(flag == false) {
                flag = true;
            }else {
                throw new RuntimeException("不要试图用反射破坏单例");
            }
        }

    }
    //创建自身对象,当时不用立即加载 volatile作用：尽大可能的解决极端情况的问题
    private volatile static SingletonDemo03 instance;

    //全局公开的方法  synchronized作用：加锁  多线程进来时会不安全，效率较低
    public static SingletonDemo03 getInstance() {
        if(instance == null) {
            //定一次进来时加锁，后面进来时就不加锁了，提高了效率
            synchronized (SingletonDemo03.class) {
                if(instance == null) {
                    instance = new SingletonDemo03();
                }
            }
        }
        return instance;
    }

}

class SingletonDemo03Test {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        /*
        SingletonDemo03 instance1 = SingletonDemo03.getInstance();
        SingletonDemo03 instance2 = SingletonDemo03.getInstance();

        System.out.println(instance1 == instance2);
*/
        Class<SingletonDemo03> clazz = SingletonDemo03.class;

        //反射破坏单例
        Constructor<SingletonDemo03> declaredConstructor = clazz.getDeclaredConstructor(null);

        declaredConstructor.setAccessible(true);

        SingletonDemo03 instance1 = declaredConstructor.newInstance();

        //破坏flag
        Field flag = clazz.getDeclaredField("flag");
        flag.setAccessible(true);
        flag.set(clazz,false);
        System.out.println(flag.get(clazz));


        SingletonDemo03 instance2 = declaredConstructor.newInstance();

        System.out.println(instance1 == instance2);

        System.out.println(instance1.hashCode());
        System.out.println(instance2.hashCode());
    }
}
